package com.cskaoyan.shiro;

import com.cskaoyan.bean.po.*;
import com.cskaoyan.mapper.MarketAPIMapper;
import com.cskaoyan.mapper.MarketAdminMapper;
import com.cskaoyan.mapper.MarketPermissionMapper;
import com.cskaoyan.mapper.MarketUserMapper;
import com.cskaoyan.util.StringUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 楚夏三分
 * @datetime 2023/1/1 11:01
 * @description: TODO: 继承AuthorizingRealm，并且注册为容器中的组件
 * TODO: 重写里面的 doGetAuthenticationInfo 和 doGetAuthorizationInfo 方法
 */
@Component
public class CustomRealm extends AuthorizingRealm {
    @Autowired
    MarketAdminMapper adminMapper;
    @Autowired
    MarketUserMapper userMapper;
    @Autowired
    MarketPermissionMapper permissionMapper;
    @Autowired
    private MarketAPIMapper apiMapper;

    /**
     * TODO: 认证
     *
     * @param authenticationToken 形参来自subject的login方法
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        // String username = token.getUsername();

        // getPrincipal()继承自AuthenticationToken, UsernamePasswordToken重写的方法调用会直接返回Username
        // String username = (String) authenticationToken.getPrincipal();

        MarketToken marketToken = (MarketToken) authenticationToken;
        String username = marketToken.getUsername();
        String type = marketToken.getType();

        if ("admin".equals(type)) {
            // 根据username查询数据库中对应的password
            MarketAdminExample example = new MarketAdminExample();
            if (!StringUtil.isEmpty(username)) {
                example.createCriteria().andUsernameEqualTo(username);
            }
            List<MarketAdmin> marketAdmins = adminMapper.selectByExample(example);
            if (marketAdmins.size() == 1) {
                MarketAdmin marketAdmin = marketAdmins.get(0);
                return new SimpleAuthenticationInfo(marketAdmin, marketAdmin.getPassword(), getName());
            }
        }else if ("wx".equals(type)){
            MarketUserExample example = new MarketUserExample();
            if (!StringUtil.isEmpty(username)) {
                example.createCriteria().andUsernameEqualTo(username);
            }
            List<MarketUser> users = userMapper.selectByExample(example);
            if (users.size() == 1) {
                MarketUser marketUser = users.get(0);
                return new SimpleAuthenticationInfo(marketUser, marketUser.getPassword(), getName());
            }
        }
        return null;
    }

    /**
     * TODO: 根据用户信息拿到所有的授权(数据库)
     *
     * @param principalCollection doGetAuthenticationInfo方法返回值的第一个参数
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // principal主体鉴定后的参数信息
        MarketAdmin principal = (MarketAdmin) principalCollection.getPrimaryPrincipal();
        if (getAdminPerms(principal.getUsername()).get(0).equals("*")){
            ArrayList<String> perms = new ArrayList<>();
            perms.add("*");
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addStringPermissions(perms);
            return simpleAuthorizationInfo;
        }
        List<String> permissions = getAdminPerms(principal.getUsername()).stream()
                .map(perm->perm.replace("/",":"))
                .map(perm2->perm2.replaceFirst(":",""))
                .map(perm3->perm3.split(" ")[1])
                .collect(Collectors.toList());
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }

    private List<String> getAdminPerms(String username) {
        // 查询market_admin表中此admin对应的roles
        MarketAdminExample adminExample = new MarketAdminExample();
        MarketAdminExample.Criteria criteria = adminExample.createCriteria();
        // 我突然发现criteria这玩意跟stream流一样返回自身对象,可以链式调用 <----> 优雅, 永不过时
        criteria.andUsernameEqualTo(username).andDeletedEqualTo(false);
        List<MarketAdmin> marketAdminsList = adminMapper.selectByExample(adminExample);

        // Stream流获取marketAdminsList中的roleIds
        // stream表示开启流式操作
        // findFirst表示取出list中第一个对象
        // orElse表示流中对象not null则返回对象本身, null则返回orElse函数中的对象
        Integer[] roleIds = marketAdminsList.stream()
                .findFirst().orElse(new MarketAdmin())
                .getRoleIds();


        // 查询market_permission表中角色对应的permission权限
        MarketPermissionExample2 permissionExample2 = new MarketPermissionExample2();
        // 将roleIds转换为List拼接 where role_id in 且逻辑存在的查询条件
        permissionExample2.createCriteria().andRoleIdIn(Arrays.asList(roleIds)).andDeletedEqualTo(false);
        // 设置重复distinct判断
        permissionExample2.setDistinct(true);
        // Stream流式调用获得MarketPermissionList并映射成其permission成员变量后终止流收集成为List
        List<String> permissions = permissionMapper.selectByExample2(permissionExample2).stream()
                .map(MarketPermission2::getPermission).collect(Collectors.toList());

        if (permissions.contains("*")) {
            ArrayList<String> perms = new ArrayList<>();
            perms.add("*");
            return perms;
        }

        List<String> apis = apiMapper.selectApiOfPermissions(permissions);
        return apis;
    }


}
